#include <iostream>
#include "token.h"
#include "exception.h"
#include "message.h"
#include "pubcallback.h"
#include "deliveryactionlistener.h"
#include "mqttinterfaceimpl.h"


#define debug_  1;

using namespace std;
const int  QOS = 1;

const auto TIMEOUT = std::chrono::seconds(10);

MqttInterfaceImpl::MqttInterfaceImpl()
{
}

int MqttInterfaceImpl::pub_init(const std::string&address, const std::string& clientID,
    const std::string& PERSIST_DIR)
{
    cout << "Initializing for server '" << address << "'..." << endl;
    m_pub_client = std::make_shared<mqtt::async_client>(address, clientID, PERSIST_DIR);

    PubCallBack cb;
    m_pub_client->set_callback(cb);
#if 0
    mqtt::connect_options connOpts;
    connOpts.set_keep_alive_interval(20);
    connOpts.set_clean_session(true);
    std::cout << "...OK" << std::endl;
#else
    //不清楚这个代码的具体用意，请注意：
    auto connOpts = mqtt::connect_options_builder()
        .clean_session()
        .will(mqtt::message("last", "Last data!", QOS))
        .finalize();
#endif
    cout << "  ...OK" << endl;

    try
    {
        cout << "\nConnecting..." << endl;
        mqtt::token_ptr conntok = m_pub_client->connect(connOpts);
        cout << "Waiting for the connection..." << endl;
        conntok->wait();
        cout << "  ...OK" << endl;

//        // Disconnect
//        cout << "\nDisconnecting..." << endl;
//        client.disconnect()->wait();
//        cout << "  ...OK" << endl;
    }
    catch (const mqtt::exception& exc)
    {
        cerr << exc.what() << endl;
        return 1;
    }

    return 0;
}

int MqttInterfaceImpl::pub_data(const string &topic, const string &data, const int qos)
{
    try
    {
        cout << "\nSending message...";
#if 0
        // First use a message pointer.
        pubmsg = mqtt::make_message(topic, data);
        pubmsg->set_qos(qos);
        m_pub_client->publish(pubmsg)->wait_for(TIMEOUT);
        cout << "  ...OK" << endl;
#endif

        // Now try with itemized publish.
#if 0
        cout << "\nSending next message..." << endl;
        mqtt::delivery_token_ptr pubtok;
        pubtok = m_pub_client->publish(TOPIC, PAYLOAD2, strlen(PAYLOAD2), QOS, false);
        cout << "  ...with token: " << pubtok->get_message_id() << endl;
        cout << "  ...for message with " << pubtok->get_message()->get_payload().size()
             << " bytes" << endl;
        pubtok->wait_for(TIMEOUT);
        cout << "  ...OK" << endl;

        // Now try with a listener
        ActionListen listener;
        pubmsg = mqtt::make_message(topic, data);
        pubmsg->set_qos(qos);
        auto pubtok = m_pub_client->publish(pubmsg, nullptr, listener);

        pubtok->wait();
        cout << "  ...OK" << endl;

#else
        // Finally try with a listener, but no token

        //cout << __LINE__ << endl;
        DeliveryActionListener deliveryListener;
        pubmsg = mqtt::make_message(topic, data);

		if(nullptr == m_pub_client)
		{
			cout << " client is null!\n";
		}

        m_pub_client->publish(pubmsg, nullptr, deliveryListener);

        while (!deliveryListener.is_done())
        {
            this_thread::sleep_for(std::chrono::milliseconds(100));
        }
        cout << ".... OK" << endl;
#endif
        // Double check that there are no pending tokens

        auto toks = m_pub_client->get_pending_delivery_tokens();
        if (!toks.empty())
            cout << "Error: There are pending delivery tokens!" << endl;

		// Disconnect
		cout << "\nDisconnecting..." << endl;
		m_pub_client->disconnect()->wait();
		cout << "  ...OK" << endl;

    }
    catch (const mqtt::exception& exc)
    {
        cerr << exc.what() << endl;
        return 1;
    }

    return 0;
}

